#pragma once

#include <amp.h>
#include <amp_math.h>
using namespace concurrency;
//using namespace concurrency::fast_math;

#include "Model.h"


enum MultiVariate { None, MultiUnderlying, Dates };

class Option
{
public:
    //virtual FLOAT payoff(vector<FLOAT> paths) =0;
    FLOAT payoff(FLOAT path);
    //MultiVariate MV() =0;
    //int Dimensions() =0;
};

class European 
{
public: 
    European(FLOAT maturity, FLOAT strike)
        : _maturity(maturity), _strike(strike)
    {}

    FLOAT maturity() const restrict (cpu, amp) { return _maturity; }
    FLOAT strike() const restrict (cpu, amp) { return _strike; }

    int Dimensions() const { return 1; }
    MultiVariate MV() const { return MultiVariate::None; }
    //vector<FLOAT> Spots() { return vector<FLOAT>(1, spot()); }
    //vector<FLOAT> Vols() { return vector<FLOAT>(1, vol()); }
    
        /*FLOAT payoff(vector<FLOAT> paths) 
        { 
        return max(paths[0] , 0.0f);
        }*/

    FLOAT payoff(FLOAT path, FLOAT df) const restrict(cpu, amp)
    {
        return df * max(path - _strike, (FLOAT)0.0);
    }

    double closedForm(FLOAT spot, FLOAT rate, FLOAT vol) const 
    {
        return BlackScholes::closedForm(spot, _strike, _maturity, rate, vol);
    }
private:
    FLOAT _strike, _maturity;
};

class Forward
{
public: 
    Forward(FLOAT maturity, FLOAT strike)
        : _maturity(maturity), _strike(strike)
    {}

    FLOAT maturity() const restrict (cpu, amp) { return _maturity; }
    FLOAT strike() const restrict (cpu, amp) { return _strike; }

    int Dimensions() const { return 1; }
    MultiVariate MV() const { return MultiVariate::None; }
    //vector<FLOAT> Spots() { return vector<FLOAT>(1, spot()); }
    //vector<FLOAT> Vols() { return vector<FLOAT>(1, vol()); }
    
        /*FLOAT payoff(vector<FLOAT> paths) 
        { 
        return max(paths[0] , 0.0f);
        }*/

    FLOAT payoff(FLOAT path, FLOAT df) const restrict(cpu, amp)
    {
        return df * (path - _strike);
    }

    double closedForm(FLOAT spot, FLOAT rate, FLOAT vol) const 
    {
        return spot - _strike;
    }
private:
    FLOAT _maturity, _strike;
};


